﻿#include "cmdarena.h"
#include "commmsg.h"
#include "../mainctrl.h"
#include "../cmd/dataprepare.h"
#include "../arena/CArenaMgr.h"
#include "../item/CItemMgr.h"
#include "MsgArena.pb.h"
#include "../cmd/cmdapi.h"

CT_REGISTER_ASYNCCMD(ID_MAIN_ARENA , CCmdArena);

int CCmdArena::Do(void* pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_ARENA ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_ARENA,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    bHasCheckSenWord = false;
    LogicDo(RET_OK);
    return iRet;
}

int CCmdArena::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, uiGID);
    ASSERT_PLAYER_PREPARED(uiGID);

    PREPARE_PLAYER_DETAIL_INFO(this, uiGID);
    ASSERT_PLAYER_DETAIL_PREPARED(uiGID);

    PREPARE_PLAYER_DETAIL_EX1_INFO(this, uiGID);
    ASSERT_PLAYER_DETAIL_EX1_INFO(uiGID);

    PREPARE_PLAYER_SNS_DETAIL_INFO(this, uiGID);

    PREPARE_PLAYER_ONLINE_DATA(this, uiGID);

    int iIndex = 0;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", uiGID));
        return AnsClients(RET_SYS_ERROR);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", uiGID));
        return AnsClients(RET_SYS_ERROR);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];
    stPlayerDetailInfo._stUserArenaData._uiGID = uiGID;

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user detail ex1 info error, uid = %u", uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("gid = %u", uiGID));
        return AnsClients(RET_SYS_ERROR);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_13, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    unsigned char ucOpt = stReq.opt();
    stAns.set_opt(ucOpt);

    bool bNeedSaveBaseInfo = false;
    bool bNeedSaveDetailInfo = false;

    switch(ucOpt)
    {
    case 1: //查询竞技场信息
        {
            //检查用户
            CArenaRank stArenaRank;
            iRet = pstMainCtrl->m_stArenaMgr.GetRankInfo(uiGID, stArenaRank);
            if (iRet == ERROR_ARENA_NO_RANK_DATA)
            {
                stArenaRank._uiGID = uiGID;
                iRet = pstMainCtrl->m_stArenaMgr.AddNewUser(stArenaRank, pstMainCtrl->m_iNow);
                if (iRet != 0)
                {
                    return AnsClients(iRet);
                }

                //统计
                pstMainCtrl->m_stAcademyMgr.ArenaChange(uiGID, stArenaRank.GetRank() ,stPlayerBaseInfo._ucAcademy);
            }

            CTSizeString<50> szTemp;
            stAns.set_name(stPlayerBaseInfo._sRoleName());
            szTemp.Set("%lld", stPlayerBaseInfo._i64Silver);
            stAns.set_silver(szTemp());
            stAns.set_reputation(stPlayerDetailInfo._iReputation);
        
            iRet = pstMainCtrl->m_stArenaMgr.GetUserArenaInfo(stPlayerDetailInfo._stUserArenaData, uiGID, pstMainCtrl->m_iNow, stAns);
            iRet = pstMainCtrl->m_stArenaMgr.GetHeroGID(stAns);
        }
        break;
    case 2: //查看战力趋势
        {
            MsgDataHis* pstMsgDataHis = stAns.mutable_data_his();
            for (int i = 0; i < stPlayerDetailInfo._stBattleFightingHis._aiDataHis.Size(); ++i)
            {
                pstMsgDataHis->add_data(stPlayerDetailInfo._stBattleFightingHis._aiDataHis[i]);
            }
        }
        break;
    case 3: //查看排名趋势
        {
            MsgDataHis* pstMsgDataHis = stAns.mutable_data_his();
            for (int i = 0; i < stPlayerDetailInfo._stUserArenaData.stRankHis._aiDataHis.Size(); ++i)
            {
                pstMsgDataHis->add_data(stPlayerDetailInfo._stUserArenaData.stRankHis._aiDataHis[i]);
            }
        }   
        break;
    case 7: //查看英雄榜
        {
            iRet = pstMainCtrl->m_stArenaMgr.GetHeroList(stAns);
        }
        break;
    case 9: //挑战
        {
            unsigned char ucAtkPos = stReq.atk_pos();

            //获取对手信息
            unsigned int uiOppGID = 0;
            iRet = pstMainCtrl->m_stArenaMgr.GetOppByPos(uiGID, ucAtkPos, uiOppGID);
            if (iRet != RET_OK)
            {
                return AnsClients(iRet);
            }

            //检查是否可以挑战
            iRet = pstMainCtrl->m_stArenaMgr.CheckAtkOpp(uiGID, uiOppGID, stPlayerDetailInfo._stUserArenaData, pstMainCtrl->m_iNow);
            if (iRet != RET_OK)
            {
                return AnsClients(iRet);
            }

            //准备防御方数据
            PREPARE_PLAYER_DETAIL_INFO(this, uiOppGID);
            PREPARE_PLAYER_BASE_INFO(this, uiOppGID);
            PREPARE_PLAYER_SNS_DETAIL_INFO(this, uiOppGID);
            PREPARE_PLAYER_ONLINE_DATA(this, uiOppGID);

            iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(uiOppGID);
            if (iIndex < 0)
            {
                CT_ERROR(("gid = %u", uiOppGID));
                return AnsClients(RET_SYS_ERROR);
            }

            iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(uiOppGID);
            if (iIndex < 0)
            {
                CT_ERROR(("gid = %u", uiOppGID));
                return AnsClients(RET_SYS_ERROR);
            }
            CPlayerDetailInfo& stDefPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

            iIndex = pstMainCtrl->m_stPlayerSnsDetailInfoHash.HashFind(uiOppGID);
            if (iIndex < 0)
            {
                CT_ERROR(("gid = %u", uiOppGID));
                return AnsClients(RET_SYS_ERROR);
            }

            iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(uiOppGID);
            if (iIndex < 0)
            {
                return AnsClients(RET_SYS_ERROR);
            }

            //准备SNS数据
            iRet = pstMainCtrl->m_stArenaMgr.AtkOppOverDataPrepare(uiGID, uiOppGID, this);
            if (RET_DATA_NOT_READY == iRet)
            {
                return RET_DATA_NOT_READY;
            }
            else if (iRet != 0)
            {
                return AnsClients(iRet);
            }

            //战斗
            CBattlePvPData stPvPData;
            stPvPData._auiLeftRole.AddOneItem(uiGID);
            stPvPData._auiRightRole.AddOneItem(uiOppGID);

            MsgBattleResult* pstMsgBattleResult = stAns.mutable_battle_result();
            MsgBattleExtInfo* pstMsgBattleExtInfo = pstMsgBattleResult->mutable_battle_ext_info();
            pstMsgBattleExtInfo->set_map_id(5050001);

            iRet = pstMainCtrl->m_stBattleMgr.DealPvPBattle(stPvPData, *pstMsgBattleResult, ACT_TYPE_ARENA);
            if (iRet != RET_OK)
            {
                return AnsClients(iRet);
            }
                
            //设置胜利
            bool bIsWin = (pstMsgBattleResult->result() == BATTLE_RESULT_WIN);

            //设置胜利宣言
            pstMsgBattleResult->set_battle_speak(bIsWin ? stPlayerDetailInfo._stUserArenaData._szWinSay() :
                                                          stDefPlayerDetailInfo._stUserArenaData._szWinSay());

            //保存录像
            T_VIDEO_KEY szVideoKey;
            pstMainCtrl->BattleToMemoryDBWithPB(szVideoKey, uiGID, BATTLE_VIDEO_TYPE_ARENA, *pstMsgBattleResult, 2591999);

            iRet = pstMainCtrl->m_stArenaMgr.AtkOppOver(uiGID, stPlayerDetailInfo._stUserArenaData, 
                                        uiOppGID, stDefPlayerDetailInfo._stUserArenaData, pstMainCtrl->m_iNow, szVideoKey, bIsWin);
            if (iRet != 0)
            {
                return AnsClients(iRet);
            }

            //触发任务
            pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_106, 1);

            //新手目标
            if (bIsWin)
            {
                pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, uiGID, NEWBIE_TASK_COND_8, 1);
            }

            //保存防御方信息
            CVarObjectKey stKey;
            stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
            stKey.m_u64ID = stDefPlayerDetailInfo._uiGID;
            pstMainCtrl->UpdateData(stKey, stDefPlayerDetailInfo, VOP_UPDATE);

            //发送奖励
            CDropItem stDropItem;
            if (bIsWin)
            {
                stDropItem.DropReputation(10);
                stDropItem.DropSilver(200 * (89 + stPlayerBaseInfo._shLevel));
            }
            else
            {
                stDropItem.DropReputation(5);
                stDropItem.DropSilver(150 * (89 + stPlayerBaseInfo._shLevel));
            }

            stDropItem.SetOssModule(OSS_MODULE_ARENA);
            iRet = pstMainCtrl->m_stItemMgr.DropItem(NULL, uiGID, stDropItem);
            if (iRet != RET_OK)
            {
                CT_WARNING(("send bonus error, ret %d, gid %d", iRet, uiGID));
            }
            else
            {
                for (int i = 0; i < stDropItem._astDropItem.Size(); ++i)
                {
                    MsgArenaBonus* pstMsgArenaBonus = stAns.add_bonus();
                    pstMsgArenaBonus->set_type(stDropItem._astDropItem[i]._ucItemType);
                    pstMsgArenaBonus->set_count(stDropItem._astDropItem[i]._iItemCount);
                }
            }

            //设置返回消息
            CTSizeString<50> szTemp;
            stAns.set_name(stPlayerBaseInfo._sRoleName());
            szTemp.Set("%lld", stPlayerBaseInfo._i64Silver);
            stAns.set_silver(szTemp());
            stAns.set_reputation(stPlayerDetailInfo._iReputation);

            CArenaRank stArenaRank;
            pstMainCtrl->m_stArenaMgr.GetRankInfo(uiGID, stArenaRank);
            stAns.set_max_rank(stArenaRank._iMaxRank);
            stAns.set_con_win(stArenaRank.GetConWinCount(pstMainCtrl->m_iNow));
            stAns.set_now_rank(stArenaRank.GetRank());
            stAns.set_left_count(stPlayerDetailInfo._stUserArenaData.GetCanFightCount(pstMainCtrl->m_iNow));

            iRet = pstMainCtrl->m_stArenaMgr.GetUserArenaInfo(stPlayerDetailInfo._stUserArenaData, uiGID, pstMainCtrl->m_iNow, stAns);
            
            //统计
            if (bIsWin)
            {
                pstMainCtrl->m_stAcademyMgr.ArenaChange(uiGID, stArenaRank.GetRank() ,stPlayerBaseInfo._ucAcademy);
            }

            //trigger daily task
            pstMainCtrl->m_stDailyTaskMgr.TriggerTaskFinish(stPlayerOnlineData._stUserDailyTask, DAILY_TASK_ID_24);

            bNeedSaveDetailInfo = true;
        }
        break;
    case 11: // 设置胜利宣言
        {
            CTSizeString<ARENA_MAX_WIN_SAY_LEN> szWinSay;
            szWinSay.Set("%s", stReq.win_say().c_str());

            if (stPlayerOnlineData._bIsTencentLogin && !bHasCheckSenWord)
            {
                bHasCheckSenWord = true;

                iRet = CheckWinSay(szWinSay);
                if (iRet != RET_OK)
                {
                    return AnsClients(iRet);
                }

                //在平台检查
                if (szWinSay.GetDataLen() > 0 && stPlayerOnlineData._bIsTencentLogin)
                {
                    CCmdApi* pstCmd = (CCmdApi*)CT_CMDFACTORY->CreateCmd(ID_MAINAPI_TAPI);
                    if (!pstCmd)
                    {
                        CT_WARNING(("create cmd error"));
                        return AnsClients(RET_SYS_ERROR);
                    }

                    pstCmd->pstMainCtrl = CMainCtrl::m_pstMain;
                    pstCmd->stReq._ucReqType = CReqApi::API_TENCENT;
                    pstCmd->stReq._szTApiName.Set("/v3/csec/word_filter");
                    pstCmd->stReq._stTApiKeyValue = stPlayerOnlineData._stTencentApiKeyValue;
                    pstCmd->stReq._stTApiKeyValue.SetValue("content", szWinSay());

                    uint64 u64MsgID = CT_UINT64_MAKE(uiGID, pstMainCtrl->m_iNow);
                    pstCmd->stReq._stTApiKeyValue.SetValue("msgid", CTStringUtils::Uint64ToString(u64MsgID, 16));

                    RegisterChild(pstCmd, true);
                    return pstCmd->Do(NULL);
                }   
            }
            else 
            {
                if (m_pstChild && ID_MAINAPI_TAPI == m_pstChild->GetCmdID())
                {
                    CCmdApi* pstCmd = (CCmdApi*)m_pstChild;
                    if (pstCmd->stReq._szTApiName == "/v3/csec/word_filter")
                    {
                        if (atoi(pstCmd->stAns._stTApiKeyValue.GetValue("is_dirty")) != 0)
                        {
                            if (strcmp("文本中有敏感词", pstCmd->stAns._stTApiKeyValue.GetValue("msg")) == 0)
                            {
                                return AnsClients(ERROR_HAS_SEN_WORD);
                            }
                            else
                            {
                                szWinSay.Set("%s", pstCmd->stAns._stTApiKeyValue.GetValue("msg"));
                            } 
                        }
                    }
                }
            }

            stPlayerDetailInfo._stUserArenaData._szWinSay = szWinSay;
            stAns.set_win_say(szWinSay());
            bNeedSaveDetailInfo = true;
        }
        break;
    case 12: // 购买挑战次数
        {
            iRet = pstMainCtrl->m_stArenaMgr.BuyBattleCount(stPlayerDetailInfo._stUserArenaData, pstMainCtrl->m_iNow, stPlayerBaseInfo._iGold);
            stAns.set_left_count(stPlayerDetailInfo._stUserArenaData.GetCanFightCount(pstMainCtrl->m_iNow));
            stAns.set_buy_battle_count(stPlayerDetailInfo._stUserArenaData.GetBuyFightCount(pstMainCtrl->m_iNow));

            if (iRet == RET_OK)
            {
                pstMainCtrl->m_stNotifyMgr.Notify(uiGID, NOTIFY_USER_MONEY);
                bNeedSaveBaseInfo = true;
                bNeedSaveDetailInfo = true;
            }
        }
        break;
    case 13: //刷新战斗时间
        {
            iRet = pstMainCtrl->m_stArenaMgr.BuyFlushBattleTime(stPlayerDetailInfo._stUserArenaData, pstMainCtrl->m_iNow, stPlayerBaseInfo._iGold);
            stAns.set_buy_flush_battle_time_count(stPlayerDetailInfo._stUserArenaData.GetBuyFlushFightCount(pstMainCtrl->m_iNow));
            stAns.set_next_battle_time(stPlayerDetailInfo._stUserArenaData._iCanFightTime);

            if (iRet == RET_OK)
            {
                pstMainCtrl->m_stNotifyMgr.Notify(uiGID, NOTIFY_USER_MONEY);
                bNeedSaveBaseInfo = true;
                bNeedSaveDetailInfo = true;
            }
        }
        break;
    default:
        return AnsClients(RET_SYS_ERROR);
    }

    //保存数据
    if (bNeedSaveBaseInfo)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }

    if (bNeedSaveDetailInfo)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
        stKey.m_u64ID = stPlayerDetailInfo._uiGID;
        CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);
    }

    return AnsClients(iRet);
}

int CCmdArena::AnsClients(int iRet)
{
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    CMainCtrl::m_pstMain->m_stEncodeBuf.Clear();
    CMainCtrl::m_pstMain->EncodePBMsg(stMsgHead, CMainCtrl::m_pstMain->m_stEncodeBuf);
    CMainCtrl::m_pstMain->EncodePBMsg(stAns, CMainCtrl::m_pstMain->m_stEncodeBuf);
    pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true);

    return Done(iRet);
}

int CCmdArena::CheckWinSay(CTSizeString<ARENA_MAX_WIN_SAY_LEN>& szWinSay)
{
    int iRet = 0;

    if (szWinSay.GetDataLen() == 0)
    {
        return 0;
    }

    //检查字符集编码方式
    const char * sNowCharSet = pstMainCtrl->m_stCharSetConvertMgr.GetCharset(szWinSay(), szWinSay.GetDataLen(), iRet);
    if (sNowCharSet == NULL || iRet != 0)
    {
        CT_WARNING(("ret = %d, char set %s", iRet, (sNowCharSet == NULL ? "NULL" : sNowCharSet)));
        return ERROR_ARENA_WIN_SAY;
    }

    if (strncmp("UTF-8", sNowCharSet, sizeof("UTF-8")) != 0
        && strlen(sNowCharSet) != 0)
    {
        CT_WARNING(("char set %s, win say = %s", (sNowCharSet == NULL ? "NULL" : sNowCharSet), szWinSay()));
        return ERROR_ARENA_WIN_SAY;
    }

    //检查长度
    int iLen = CTStringUtils::GetUtf8StrLen(szWinSay());
    if (iLen >= ARENA_MAX_WIN_SAY_LEN_BYTE)
    {
        return ERROR_ARENA_WIN_SAY_TOO_LONG;
    }

    if (iLen <= 0)
    {
        return 0;
    }
    

    //检查单字节屏蔽字
    for (int i = 0; i < szWinSay.GetDataLen(); ++i)
    {
        unsigned char ucChar = szWinSay()[i];
        if (ucChar < 128)
        {
            if ((ucChar >= '0' && ucChar <= '9')
                || (ucChar >= 'a' && ucChar <= 'z')
                || (ucChar >= 'A' && ucChar <= 'Z'))
            {
                continue;
            }
            else
            {
                return ERROR_ARENA_WIN_SAY;
            }
        }
    }
   
    return 0;
}

